package com.zkthink.ceres.sms.controller;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.zkthink.base.R;
import com.zkthink.base.entity.SuperEntity;
import com.zkthink.cache.repository.CacheRepository;
import com.zkthink.ceres.common.constant.CacheKey;
import com.zkthink.ceres.sms.dto.VerificationCodeDTO;
import com.zkthink.ceres.sms.entity.SmsTask;
import com.zkthink.ceres.sms.enumeration.SourceType;
import com.zkthink.ceres.sms.enumeration.TemplateCodeType;
import com.zkthink.ceres.sms.enumeration.VerificationCodeType;
import com.zkthink.ceres.sms.service.SmsTaskService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 通用验证码
 *
 * @author ceres
 * @date 2019/08/06
 */
@Slf4j
@Validated
@RestController
@RequestMapping("/verification")
@Api(value = "VerificationCode", tags = "验证码")
public class VerificationCodeController {

  @Autowired
  private CacheRepository cacheRepository;
  @Autowired
  private SmsTaskService smsTaskService;


  @Value("${spring.profiles.active:dev}")
  private String profiles;

  /**
   * 通用的发送验证码功能
   * <p>
   * 一个系统可能有很多地方需要发送验证码（注册、找回密码等），每增加一个场景，VerificationCodeType 就需要增加一个枚举值
   */
  @ApiOperation(value = "发送验证码", notes = "发送验证码")
  @PostMapping(value = "/send")
  public R<Boolean> send(@Validated @RequestBody VerificationCodeDTO data) {
    String code = "123456";
    if (StrUtil.isNotBlank(profiles) && !"dev".equalsIgnoreCase(profiles)) {
      //生成随机6位验证码
      code = RandomUtil.randomNumbers(6);
      //创建短信任务
      SmsTask smsTask = SmsTask.builder().build();
      smsTask.setSourceType(SourceType.SERVICE);
      smsTask.setTemplateParams(buildTemplateParam(code));
      smsTask.setReceiver(data.getMobile());
      smsTask.setDraft(false);
      //验证码短信 默默人为通用类型
      smsTaskService.saveTask(smsTask, getTemplateCodeType(data.getType()));
    }
    //缓存验证码
    saveCodeToCache(data, code);
    return R.success();
  }

  /**
   * 通用的发送验证码功能
   * <p>
   * 一个系统可能有很多地方需要发送验证码（注册、找回密码等），每增加一个场景，VerificationCodeType 就需要增加一个枚举值
   */
  @ApiOperation(value = "商家入驻发送验证码", notes = "商家入驻发送验证码")
  @PostMapping(value = "/send/tenantApply")
  public R<Boolean> sendTenantApplyCoee(@Validated @RequestBody VerificationCodeDTO data) {
    String code = "123456";
    if (StrUtil.isNotBlank(profiles) && !"dev".equalsIgnoreCase(profiles)) {
      //生成随机6位验证码
      code = RandomUtil.randomNumbers(6);

      //创建短信任务
      SmsTask smsTask = SmsTask.builder().build();
      smsTask.setSourceType(SourceType.SERVICE);
      smsTask.setTemplateParams(buildTemplateParam(code));
      smsTask.setReceiver(data.getMobile());
      smsTask.setDraft(false);

      //验证码短信 默默人为通用类型
      smsTaskService.saveTask(smsTask, getTemplateCodeType(data.getType()));
    }
    //缓存验证码
    saveCodeToCache(data, code);
    return R.success();
  }


  private TemplateCodeType getTemplateCodeType(VerificationCodeType type) {
    switch (type) {
      case REGISTER_USER:
        return TemplateCodeType.CODE_REGISTER_USER;
      case REGISTER_COLLECTING_ACCOUNT:
        return TemplateCodeType.CODE_COLLECTING_ACCOUNT;
      case TENANT_APPLY:
        return TemplateCodeType.CODE_TENANT_APPLY;
      default:
        return TemplateCodeType.CODE_REGISTER_USER;
    }
  }

  private void saveCodeToCache(@RequestBody @Validated VerificationCodeDTO data, String code) {
    String key = CacheKey
        .buildTenantKey(getCodeKeyPrefix(data), data.getType().name(), data.getMobile());
    cacheRepository.setExpire(key, code, CacheRepository.DEF_TIMEOUT_5M);
  }

  private String getCodeKeyPrefix(VerificationCodeDTO data) {
    switch (data.getType()) {
      case REGISTER_USER:
        return CacheKey.REGISTER_USER;
      case REGISTER_COLLECTING_ACCOUNT:
        return CacheKey.REGISTER_COLLECTING_ACCOUNT;
      case TENANT_APPLY:
        return CacheKey.TENANT_APPLY;
    }
    return CacheKey.REGISTER_USER;
  }

  private String buildTemplateParam(String code) {
    JSONObject param = new JSONObject();
    param.put("1", code);
    return param.toString();
  }

  /**
   * 对某种类型的验证码进行校验
   */
  @ApiOperation(value = "验证验证码", notes = "验证验证码")
  @PostMapping
  public R<Boolean> verification(
      @Validated(SuperEntity.Update.class) @RequestBody VerificationCodeDTO data) {
    String key = CacheKey
        .buildTenantKey(getCodeKeyPrefix(data), data.getType().name(), data.getMobile());
    String code = cacheRepository.get(key);
    return R.success(data.getCode().equals(code));
  }
}
